home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume7 / oracle < prev    next >
Encoding:
Text File  |  1989-08-05  |  18.3 KB  |  599 lines

  1. Newsgroups: comp.sources.misc
  2. organization: Cornell Univ. CS Dept, Ithaca NY
  3. subject: v07i117: oracle -- anonymous question/answer program
  4. from: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5. Reply-To: huttar@svax.cs.cornell.edu (Lars Huttar)
  6.  
  7. Posting-number: Volume 7, Issue 117
  8. Submitted-by: huttar@svax.cs.cornell.edu (Lars Huttar)
  9. Archive-name: oracle
  10.  
  11. [Two potential problems.  First, it uses loooooong filenames and will
  12. therefore have to be rewritten for System V.  Second, there is at least one
  13. place where a system() command is made with "2>&-", ostensibly to send errors
  14. to /dev/null -- in reality, this CLOSES standard error and can cause programs
  15. using stdio to dump core, so be warned.  ++bsa]
  16.  
  17. Oracle is a fun sort of 'message base' program.
  18. The idea is, you run oracle and ask it a question, on any subject.
  19. Could be advice on how to make some decision, or the meaning of some word,
  20. or anything.  Later, when someone else runs oracle, they will get your
  21. question and answer it.  Oracle will mail the answer back to you, but
  22. you don't know who it's from.  So it's really just an anonymous game of
  23. questions and answers.
  24.  
  25. The Makefile tells how to build the program.  Notes tells a little about
  26. the operation of the program, but you don't need to read it to run oracle.
  27. #! /bin/sh
  28. # This is a shell archive, meaning:
  29. # 1. Remove everything above the #! /bin/sh line.
  30. # 2. Save the resulting text in a file.
  31. # 3. Execute the file with /bin/sh (not csh) to create the files:
  32. #    oracle.man
  33. #    Notes
  34. #    oracle.c
  35. #    Makefile
  36. # This archive created: Thu Aug  3 08:21:44 1989
  37. export PATH; PATH=/bin:$PATH
  38. if test -f 'oracle.man'
  39. then
  40.     echo shar: will not over-write existing file "'oracle.man'"
  41. else
  42. sed 's/^X//' << \SHAR_EOF > 'oracle.man'
  43. X.\" @(#)oracle.6 1.0 7/29/89 Lars Huttar
  44. X.\" <huttar@occs.oberlin.edu>
  45. X.TH ORACLE 6 "29 July 1989"
  46. X.SH NAME
  47. Xoracle \- answer difficult questions
  48. X.SH SYNOPSIS
  49. X.B oracle
  50. X.SH DESCRIPTION
  51. X.I Oracle
  52. Xis a program that accept questions and gives answers; if you want
  53. Xto know how to use it, just run it.  Its operation is pretty self-evident.
  54. XBut if you want to spoil the secret of how it works, read on.
  55. X.PP
  56. XEvery time someone types in a question,
  57. X.I oracle
  58. Xsaves it in a file in the
  59. X.I oracle
  60. Xdirectory.  After someone has typed in a question,
  61. X.I oracle
  62. Xlooks in this directory for questions from other users.
  63. XIt takes the oldest one in there and asks the user to answer it.
  64. XThen it mails this answer, along with a copy of the question, to
  65. Xthe person who first asked the question.
  66. X
  67. X.SH BUGS
  68. XIt's not much fun if you're the only one playing.  If you see any other
  69. Xbugs, please send them or any comments to:
  70. X.in +2
  71. X.nf
  72. XLars Huttar
  73. X<huttar@occs.oberlin.edu>
  74. X<slh6559@oberlin.bitnet>
  75. X
  76. SHAR_EOF
  77. fi # end of overwriting check
  78. if test -f 'Notes'
  79. then
  80.     echo shar: will not over-write existing file "'Notes'"
  81. else
  82. sed 's/^X//' << \SHAR_EOF > 'Notes'
  83. XLib directory:
  84. XORACLEDIR (defined in Makefile) is a
  85. Xquestion directory with one file per question.
  86. XFilename is q_username_time_hostname_processid for each file.
  87. XOne file is called "record" and contains the directory listing.
  88. XThe command system("ls -rt q_* > record") fills this file.
  89. XAnother file is "lockfile", whose existence means an oracle process is
  90. Xusing the directory to the exclusion of others.
  91. X
  92. XProcess when somebody runs *oracle*:
  93. X    A. Say "Please type in your question."  Save question in a file in
  94. X        question directory, with x_ prefix.
  95. X    B. Lock questions directory.
  96. X        Update "record" file.
  97. X        Get least recent question file -- that is the first file listed
  98. X        in "record" -- which did not come from the current user.
  99. X        Move that file to t_blahblahblah. (t for temp)
  100. X        Unlock directory.
  101. X    C. Print the question and get answer from user.
  102. X        Save to file a_blahblahblah.  Mail to original
  103. X        questioner -- system("mail user < a_blablabla").
  104. X        Move the x_ file (created in A) to q_whatever.
  105. X        Remove the t_ and a_ files -- unless the LOG flag is #defined
  106. X        in which case the a_ files are left around.
  107. X    D. Tell user the answer will reach them in a short while.  Ask user
  108. X        to encourage friends to Ask The Oracle.
  109. X
  110. XPrefix summary:
  111. X    q_ A question file that has been stored by a previous oracle, or
  112. X       is created from the current user's question just before current
  113. X       oracle terminates.
  114. X
  115. X    t_ A question file from a different user that has been selected
  116. X       to be shown to and answered by the current user.
  117. X
  118. X    x_ Temporary file to which the question of the current user is written
  119. X       as it is being typed.  Gets moved to q_ if everything goes smoothly.
  120. X
  121. X    a_ Answer file, exactly as the final answer message will be sent
  122. X       to the Other User whose question was selected.  So it contains
  123. X       introductory remarks, a copy of the Other User's question,
  124. X       and the answer given by the current user.  This answer is written
  125. X       line-by-line as the user types it in.
  126. X
  127. X
  128. XPermissions:
  129. X    All files will be readable and writable only by the owner.
  130. XThe *oracle* program will have the setuid bit set, so that
  131. Xusers will "become" the owner while the program is running.
  132. XIn order to have mail messages appear to be from the owner of oracle,
  133. Xthe real uid of the process is set to the effective uid just before
  134. Xmailing occurs.
  135. X
  136. X
  137. X
  138. XAccessing the directory:
  139. X    Attempt to cd there before anything starts.  If we fail, quit.
  140. X
  141. XLog:
  142. X    If a certain flag LOG is #defined, q_ and a_ files will
  143. Xbe left undeleted in the oracle directory.
  144. X
  145. X
  146. XTo do:
  147. X    After the question is entered, the oracle should have the person
  148. Xconfirm, "Do you still want to send this question to the oracle?"
  149. X    If DEBUG is defined, check upon startup (a) whether the file
  150. Xargv[0] has the setuid bit set, and (b) whether it has worked (on some
  151. Xfilesystems it may be ignored for security reasons).
  152. X    Enter cbreak mode so that if the user tries ^C, the program can
  153. Xexit gracefully, restoring any q_file it might have moved to t_, and
  154. Xremoving any created files that are to be abandoned (including lockfile,
  155. Xx_whatever, and a_whatever).
  156. X    Allow a file to be specified as a command-line argument, that oracle
  157. Xwill read the question from.
  158. X
  159. SHAR_EOF
  160. fi # end of overwriting check
  161. if test -f 'oracle.c'
  162. then
  163.     echo shar: will not over-write existing file "'oracle.c'"
  164. else
  165. sed 's/^X//' << \SHAR_EOF > 'oracle.c'
  166. X/*
  167. X * Copyright 1989 Lars Huttar
  168. X *
  169. X * Permission to use, copy, modify, and distribute this software and its
  170. X * documentation for any purpose and without fee is hereby granted, provided
  171. X * that the above copyright notice appear in all copies and that both that
  172. X * copyright notice and this permission notice appear in supporting
  173. X * documentation, and that the name of Lars Huttar not be used in advertising
  174. X * or publicity pertaining to distribution of the software without specific,
  175. X * written prior permission.  Lars Huttar makes no representations about the
  176. X * suitability of this software for any purpose.  It is provided "as is"
  177. X * without express or implied warranty.
  178. X *
  179. X * LARS HUTTAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  180. X * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
  181. X * SHALL LARS HUTTAR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  182. X * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  183. X * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
  184. X * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
  185. X * THIS SOFTWARE.
  186. X *
  187. X * Author:  Lars Huttar, Oberlin College
  188. X *          huttar@occs.oberlin.edu
  189. X *          slh6559@oberlin.bitnet
  190. X */
  191. X
  192. X#include <stdio.h>
  193. X#include <sys/param.h>
  194. X   /*  ^^ defines MAXHOSTNAMELEN */
  195. X#include <sys/time.h>
  196. X#include <errno.h>
  197. X#include <pwd.h>
  198. X
  199. X#ifndef L_cuserid
  200. X#define L_cuserid 50
  201. X#endif
  202. Xint errno;
  203. X
  204. X#define MAXPNLEN 50  /* That's being generous. */
  205. Xstatic char progname[MAXPNLEN], loginname[L_cuserid];
  206. X   /* L_cuserid is defined in stdio.h on some systems,
  207. X      and is the max length of login names. */
  208. Xint lognamlen;
  209. X
  210. X
  211. Xusage()
  212. X{  fprintf(stderr, "Usage: %s\n", progname);
  213. X   exit(1);
  214. X}
  215. X
  216. Xmain(argc, argv)
  217. Xint argc;
  218. Xchar **argv;
  219. X{  char *ks, *getlogin();
  220. X   struct passwd *kp;
  221. X
  222. X#ifdef DEBUG
  223. X   kp=getpwuid(geteuid());
  224. X   printf("euid: %d %s\n", geteuid(), kp->pw_name);
  225. X#endif
  226. X
  227. X   if (chdir(ORACLEDIR))   /* Try to go to the directory. */
  228. X      my_error("error in main(): Couldn't chdir to ", ORACLEDIR);
  229. X
  230. X   if (!(ks = getlogin()))
  231. X   {  if (!(kp = getpwuid(getuid())))
  232. X         my_error("error in main(): Couldn't get username.", "");
  233. X      else strcpy(loginname, kp->pw_name);
  234. X   }
  235. X   else strcpy(loginname, ks);
  236. X   lognamlen=strlen(loginname);
  237. X
  238. X   strncpy(progname, argv[0], MAXPNLEN-1);
  239. X   progname[MAXPNLEN-1]=NULL;
  240. X
  241. X   if (argc>1) usage();
  242. X
  243. X   get_question();
  244. X   get_answer();
  245. X   update_records();
  246. X   farewell();
  247. X
  248. X
  249. X}
  250. X
  251. X
  252. X#define MAXDATESIZE 30
  253. X#define MAXFNSIZE (MAXHOSTNAMELEN+L_cuserid+MAXDATESIZE+6)
  254. Xstatic char q_filename[MAXFNSIZE], a_filename[MAXFNSIZE];
  255. X
  256. X#define MAXLINELEN 141
  257. X
  258. X/** This function, get_question(), asks the user to type in a question.
  259. X ** The question is written line by line to a temporary file x_blahblahblah.
  260. X */
  261. X
  262. Xget_question()
  263. X{  char line[MAXLINELEN];
  264. X   FILE *outfp;
  265. X   register int lines=0;
  266. X
  267. X   make_filename();
  268. X   q_filename[0]='x';   /* This means it's a temporary question file. */
  269. X
  270. X   if (!(outfp=fopen(q_filename, "w")))
  271. X      my_error("error in get_question(): Couldn't open file for writing: ",
  272. X        q_filename);
  273. X
  274. X   puts("I am the oracle.  I can answer any question");
  275. X   puts("in roughly constant time.  Please type in");
  276. X   puts("your question.  Enter a blank line when");
  277. X   puts("you are finished (don't use ^D!).\n");
  278. X
  279. X   do
  280. X   {  putchar('>'); putchar(' ');
  281. X      if (!fgets(line, MAXLINELEN-1, stdin) || line[0]=='\n') break;
  282. X      lines=1;
  283. X      line[MAXLINELEN-1]=0;
  284. X      fputs(line, outfp);
  285. X   } while (!feof(stdin));
  286. X
  287. X   clearerr(stdin);
  288. X   fclose(outfp);
  289. X
  290. X   if (!lines)
  291. X   {  puts("Ask a null question, get a null answer.");
  292. X      if (unlink(q_filename))
  293. X         my_error("error in get_question: Couldn't unlink ", q_filename);
  294. X      exit(1);
  295. X   }
  296. X}
  297. X
  298. X
  299. Xint got_answer=0;
  300. X
  301. Xget_answer()
  302. X{  FILE *recfp, *quesfp, *ansfp;
  303. X   char line[MAXLINELEN];
  304. X   register int lines=0, num;
  305. X
  306. X   puts("\nHmmm.  I'll have to think about that one for a while.");
  307. X
  308. X  /** Look for a suitable question file. */
  309. X
  310. X   if (lock_directory()) return;
  311. X      /* Couldn't lock the directory, so don't require an answer. */
  312. X
  313. X   system("ls -rt q_* > record 2>&-"); /* stderr goes to /dev/null */
  314. X   if (!(recfp=fopen("record", "r")))  /* Open the file containing list of
  315. X                                        * question files */
  316. X      my_error("in get_answer(): fopen(\"record\", \"r\") gave error.", "");
  317. X
  318. X   do
  319. X   {  
  320. X      fgets(a_filename, MAXFNSIZE, recfp);
  321. X      if (feof(recfp)) break;
  322. X
  323. X      if (strncmp(a_filename+2, loginname, lognamlen))
  324. X         break;   /* found a question from a different user */
  325. X   } while (!feof(recfp));
  326. X
  327. X   if (feof(recfp))  /* Didn't find a suitable question file. */
  328. X   {  fclose(recfp);
  329. X      unlock_directory();
  330. X      return;
  331. X   }
  332. X   fclose(recfp);
  333. X
  334. X   a_filename[strlen(a_filename)-1]=(char)NULL; /* Take away final newline */
  335. X
  336. X   {  char nufilename[MAXFNSIZE];
  337. X
  338. X      strcpy(nufilename, a_filename);
  339. X      nufilename[0]='t';   /* Rename it so other oracles will not answer it. */
  340. X      if (rename(a_filename, nufilename))
  341. X         my_error("Error in get_answer() renaming file ", a_filename);
  342. X   }
  343. X
  344. X
  345. X   unlock_directory();
  346. X
  347. X
  348. X  /** Ask user to answer question. */
  349. X
  350. X   a_filename[0]='t';
  351. X   if (!(quesfp=fopen(a_filename, "r")))
  352. X      my_error("Error in get_answer() opening file for input: ", a_filename);
  353. X
  354. X   a_filename[0]='a';
  355. X   if (!(ansfp=fopen(a_filename, "w")))
  356. X      my_error("Error in get_answer() opening file for output: ", a_filename);
  357. X
  358. X   fputs("The oracle has pondered your question deeply.\n", ansfp);
  359. X   fputs("Your question was:\n\n", ansfp);
  360. X
  361. X   puts("Meanwhile, I'd like you to answer a question for me:\n");
  362. X
  363. X   while (!feof(quesfp))
  364. X   {  static int i=0;
  365. X
  366. X      fgets(line, MAXLINELEN, quesfp);
  367. X      if (!feof(quesfp))
  368. X      {  fputs("> ", stdout); fputs(line, stdout);
  369. X         fputs("> ", ansfp); fputs(line, ansfp);
  370. X      }
  371. X      if (++i % 15 == 0) get_return("Press RETURN for More--");
  372. X   }
  373. X   fclose(quesfp);
  374. X   puts("\nWhat would you say?\n");
  375. X   fputs("\nAnd in response, thus spake the oracle:\n\n", ansfp);
  376. X
  377. X   do
  378. X   {  putchar(')'); putchar(' ');
  379. X      fgets(line, MAXLINELEN-1, stdin);
  380. X      if (line[0]=='\n' && lines)
  381. X         break;
  382. X      lines++;
  383. X      line[MAXLINELEN-1]=0;
  384. X      fputs(lines%2 ? "} " : "{ ", ansfp); fputs(line, ansfp);
  385. X   } while (!feof(stdin));
  386. X
  387. X   {  static char *objects[]=
  388. X         {"cents", "of your children", "dollars", "big kisses",
  389. X          "years of slavery", "minutes of life", "newt's eyes",
  390. X          "quarts of soy sauce", "cases of root beer"};
  391. X      
  392. X      num=rand()+getpid()+getuid()+getppid();
  393. X      fprintf(ansfp, "\n\nYou owe the oracle %d %s.\n",
  394. X           num%4+2, objects[num%9]);
  395. X   }
  396. X
  397. X   fclose(ansfp);
  398. X
  399. X   switch(num%5)
  400. X   {  case 1: puts("\nHa!  What kind of answer is that?"); break;
  401. X      case 2: puts("\nNow why couldn't I think of that?"); break;
  402. X      case 3: puts("\nOk, good enough.  You pass."); break;
  403. X      default: puts("\nThank you!  That one's been troubling me.");
  404. X   }
  405. X
  406. X   got_answer=1;
  407. X}
  408. X
  409. X
  410. X#define WAITLIMIT 5
  411. X
  412. X/** This function, lock_directory, tries to lock the current directory
  413. X ** by creating a file "lockfile",
  414. X ** and returns 0 on success, 1 on failure. */
  415. Xlock_directory()
  416. X{  register int lockfd, i=0;
  417. X
  418. X   for (i=0; i<WAITLIMIT; i++)
  419. X
  420. X   {  if ((lockfd=creat("lockfile", 0)) == -1)
  421. X      {  if (errno != EACCES)
  422. X            my_error("Error in lock_directory(): creat(\"lockfile\");", "");
  423. X      }
  424. X      else
  425. X      {  if (close(lockfd) == -1)
  426. X            my_error("Error in lock_directory(): closing lockfile","");
  427. X         else return(0);
  428. X      }
  429. X
  430. X#ifdef DEBUG
  431. X      if (i==0) printf("Waiting for lock... 1");
  432. X      else printf(", %d", i+1);
  433. X      fflush(stdout);
  434. X#endif
  435. X      sleep(1);   /* Is this too long?  usleep() may be more appropriate. */
  436. X   }
  437. X
  438. X   return(1);
  439. X}
  440. X
  441. X
  442. X/** This function unlocks the current directory. */
  443. Xunlock_directory()
  444. X{
  445. X#ifdef DEBUG
  446. X   get_return("Press RETURN to unlock the directory.");
  447. X#endif
  448. X
  449. X   if (unlink("lockfile") == -1)
  450. X      my_error("Error in unlink() while trying to unlock directory.", "");
  451. X}
  452. X
  453. X
  454. Xupdate_records()
  455. X{  char command[L_cuserid+MAXFNSIZE+10], olduser[L_cuserid], newqfn[MAXFNSIZE];
  456. X   register int i;
  457. X
  458. X   strcpy(newqfn, q_filename);
  459. X   newqfn[0]='q';
  460. X   if (rename(q_filename, newqfn))
  461. X      my_error("update_records(): Error renaming file ", newqfn);
  462. X
  463. X   if (!got_answer) return;
  464. X   
  465. X   for (i=2; a_filename[i]!='_'; i++)
  466. X      olduser[i-2]=a_filename[i];
  467. X   olduser[i-2]=0;
  468. X
  469. X   if (setreuid(geteuid(), -1))  /* Make message be From the oracle owner. */
  470. X      my_error("Error in update_records(), setreuid();", "");
  471. X   sprintf(command, "mail %s < %s", olduser, a_filename);
  472. X   if (i=system(command))
  473. X   {  static char exit_code[5];
  474. X      sprintf(exit_code, "%d", i);
  475. X      my_error("Trouble mailing reply.  Exit code: ", exit_code);
  476. X   }
  477. X
  478. X
  479. X#ifndef LOG
  480. X   if (unlink(a_filename))    /* Remove the answer file (which includes
  481. X             a copy of the question)*/
  482. X      my_error("update_records(): Error unlinking ", a_filename);
  483. X#endif
  484. X   a_filename[0]='t';
  485. X   if (unlink(a_filename))    /* Remove the old question file */
  486. X      my_error("update_records(): Error unlinking ", a_filename);
  487. X
  488. X}
  489. X
  490. X
  491. X/** The function make_filename constructs a string of the form
  492. X ** q_user_date_host_processid and writes it the global string "q_filename". */
  493. Xmake_filename()
  494. X{  char hostname[MAXHOSTNAMELEN], date[MAXDATESIZE];
  495. X   long time; /* no see. */
  496. X   
  497. X   int pid;
  498. X   struct timeval tv;
  499. X   struct timezone tz;
  500. X
  501. X   if (gethostname(hostname, MAXHOSTNAMELEN)) 
  502. X      my_error("make_filename(): Had trouble getting hostname;", "");
  503. X   
  504. X
  505. X   pid=getpid();  /* Get the process id. */
  506. X   
  507. X   time=gettimeofday(&tv, &tz);  /* Get the number of seconds since
  508. X                                    that unforgettable New Year's party */
  509. X   if (time == -1) tv.tv_sec=rand();   /* Sure this isn't error-proof... */
  510. X   strncpy(date, ctime(&(tv.tv_sec))+4, 20); /* +4 to avoid day of the week. */
  511. X   date[20]=NULL; space_to__(date); /* Change spaces to _. */
  512. X
  513. X   sprintf(q_filename, "q_%s_%s_%s_%d", loginname, date, hostname, pid);
  514. X      /* Just trying to make a unique filename. */
  515. X}
  516. X
  517. Xspace_to__(string)
  518. Xchar *string;
  519. X{  register char *p;
  520. X
  521. X   for (p=string; *p; p++)
  522. X      if (*p==' ') *p='_';
  523. X}
  524. X
  525. X
  526. X
  527. X/** The following function says goodbye and advertises
  528. X ** the program. */
  529. Xfarewell()
  530. X{
  531. X   puts("\nYour answer (and your bill) will be mailed to you shortly.");
  532. X   puts("Tell all your friends to Ask the Oracle!");
  533. X}
  534. X
  535. X
  536. Xmy_error(mess1, mess2)
  537. Xchar *mess1, *mess2;
  538. X{  printf("%s%s\n", mess1, mess2);
  539. X
  540. X#ifdef DEBUG
  541. X   printf("errno: %d\n", errno);
  542. X#endif
  543. X
  544. X/* printf("EACCES %d  EBADF %d  EAGAIN %d  EINTR %d  ENOLCK %d\n",/**deleteme*/
  545. X/*    EACCES, EBADF, EAGAIN, EINTR, ENOLCK);/**deleteme*/
  546. X   perror(progname);
  547. X   exit(1);
  548. X}
  549. X
  550. X
  551. Xget_return(prompt)
  552. Xchar *prompt;
  553. X{  fputs(prompt, stdout);
  554. X   while (getchar()!='\n');
  555. X}
  556. X
  557. SHAR_EOF
  558. fi # end of overwriting check
  559. if test -f 'Makefile'
  560. then
  561.     echo shar: will not over-write existing file "'Makefile'"
  562. else
  563. sed 's/^X//' << \SHAR_EOF > 'Makefile'
  564. X# Makefile for oracle
  565. X
  566. X# To make this program, first set TARGETDIR to something appropriate.
  567. X# You may want to change LIBDIR and CFLAGS as well.
  568. X# Then 'make all'.
  569. X
  570. XTARGETDIR = /mu/huttar/oracle
  571. XLIBDIR = ${TARGETDIR}/oraclelib
  572. XCFLAGS = -DLOG -DORACLEDIR=\"${LIBDIR}\"
  573. X# -DDEBUG and -DLOG are optional.
  574. X# -DDEBUG causes extra diagnostics to be run, and
  575. X# -DLOG causes old files to be left around.
  576. X
  577. X
  578. Xall: ${TARGETDIR}/oracle ${LIBDIR}
  579. X
  580. X
  581. X${TARGETDIR}/oracle : oracle.c
  582. X    cc -o ${TARGETDIR}/oracle ${CFLAGS} oracle.c
  583. X    chmod u+s ${TARGETDIR}/oracle
  584. X
  585. X${LIBDIR} :
  586. X    mkdir ${LIBDIR}
  587. X
  588. SHAR_EOF
  589. fi # end of overwriting check
  590. #    End of shell archive
  591. exit 0
  592. -- 
  593. Lars Huttar ---------------------------- rhymes exactly with "sparse butter"
  594. huttar@svax.cs.cornell.edu ---------- The opinions and decisions are my own.
  595. After Aug 15: huttar@occs.oberlin.edu or slh6559@oberlin.bitnet -- vi rules!
  596. You can talk the talk, but can you walk the dog?
  597.  
  598.  
  599.